from typing import Dict, Optional
from nicegui import ui
from ex4nicegui import on, to_ref, ref_computed, event_batch
from ex4nicegui.reactive import rxui

from ex4nicegui.utils.signals import effect

# 参考实现
## https://nicegui.io/documentation/table#show_and_hide_columns


columns = [
    {
        "name": "name",
        "label": "Name",
        "field": "name",
        "required": True,
        "align": "left",
    },
    {"name": "age", "label": "Age", "field": "age", "sortable": True},
]

rows = [
    {"name": "Alice", "age": 18},
    {"name": "Bob", "age": 21},
    {"name": "Carol"},
]


# 纯函数，比较繁琐，每次生成新的 columns 列表
def version1():
    # 对应界面上交互的 switch
    switch_refs = [to_ref(True) for _ in range(len(columns))]

    # 这是依据 switch_refs 联动的表格 columns数据
    @ref_computed
    def colmuns_ref():
        return [
            {
                **col,
                **{
                    "classes": "" if switch_ref.value else "hidden",
                    "headerClasses": "" if switch_ref.value else "hidden",
                },
            }
            for col, switch_ref in zip(columns, switch_refs)
        ]

    @ref_computed
    def show_column_count():
        return f"当前显示的列的数量：{sum(sw.value for sw in switch_refs)}"

    # 这是可以脱离界面，验证结果
    @effect
    def _():
        pass
        # print(colmuns_ref.value)

    # ui
    rxui.table(colmuns_ref, rows, pagination=None)

    for col, switch_ref in zip(columns, switch_refs):
        rxui.switch(col["label"], value=switch_ref)

    rxui.label(show_column_count)


# 与官方示例一样，使用在修改一个固定的 columns 列表
def version2():
    # 对应界面上交互的 switch
    switch_refs = [to_ref(True) for _ in range(len(columns))]

    columns_ref = to_ref(columns)

    # 在 switch 变化时，更新 columns ref
    @on(switch_refs)
    def when_switch_changes():
        for i, sw in enumerate(switch_refs):
            columns_ref.value[i]["classes"] = "" if sw.value else "hidden"
            columns_ref.value[i]["headerClasses"] = "" if sw.value else "hidden"

        # 目前 ex4ng 响应式不支持可变对象，需要重新赋值
        columns_ref.value = columns_ref.value

    @ref_computed
    def visible_column_count():
        return sum(sw.value for sw in switch_refs)

    @ref_computed
    def visible_column_count_text():
        return f"当前显示的列的数量：{visible_column_count.value}"

    # @event_batch 可选，
    # 打上这个装饰器，可以确保在函数中国对所有响应式变量的修改，只在函数结束后才触发一次
    @event_batch
    def change_all_switch(visible: Optional[bool] = None):
        """批量修改 switch 状态

        Args:
            visible (Optional[bool], optional): None 表示反选. Defaults to None.
        """

        for sw in switch_refs:
            sw.value = (not sw.value) if visible is None else visible

    # 全部取消的按钮状态
    @ref_computed
    def all_cancel_btn_enabled():
        # 所有都在取消状态，按钮就不可点击吧
        print("all_cancel_btn_enabled")
        return visible_column_count.value > 0

    # 全部显示的按钮状态
    @ref_computed
    def all_visible_btn_enabled():
        # 只要有一个switch还没有选中，则可用
        return len(switch_refs) > visible_column_count.value

    # ui
    rxui.table(columns_ref, rows, pagination=None).classes("grow")

    for col, switch_ref in zip(columns, switch_refs):
        rxui.switch(col["label"], value=switch_ref)

    with ui.row():
        rxui.button(
            "全部取消", on_click=lambda: change_all_switch(visible=False)
        ).bind_enabled(all_cancel_btn_enabled)
        rxui.button(
            "全部显示", on_click=lambda: change_all_switch(visible=True)
        ).bind_enabled(all_visible_btn_enabled)
        ui.button("反选", on_click=lambda: change_all_switch(visible=None))

    rxui.label(visible_column_count_text)


def version_ng():
    table = ui.table(columns=columns, rows=rows, row_key="name")

    def toggle(column: Dict, visible: bool) -> None:
        column["classes"] = "" if visible else "hidden"
        column["headerClasses"] = "" if visible else "hidden"
        table.update()

    for column in columns:
        ui.switch(
            column["label"],
            value=True,
            on_change=lambda e, column=column: toggle(column, e.value),
        )


ui.card.default_classes("min-h-[60vh]")

with ui.grid(columns=3).classes("w-full"):
    with ui.card():
        ui.label("原地修改list的数据响应式")
        version2()
    with ui.card():
        ui.label("官方版本")
        version_ng()
    with ui.card():
        ui.label("无副作用修改的响应式")
        version1()


ui.run()
